Popular Searches
Popular Course Categories
Popular Courses

Implementing JWT-Based Authentication

Implementing JWT-Based Authentication

Spring Security and Secure REST APIs

Implementing JWT-Based Authentication in Spring Boot

Course: Advanced Java Training

Topic: Implementing JWT-Based Authentication

Course Link: Advanced Java Training Course

Demo Link: Register for a Course Demo

Website: JustAcademy


1. Introduction to JWT-Based Authentication

JSON Web Token (JWT) is a compact, URL-safe token format used to transmit claims between parties. In Spring Boot applications, JWTs are commonly used to authenticate users and secure REST APIs without requiring the server to maintain a traditional HTTP session for each authenticated client.

When a user successfully authenticates, an authentication system can issue a signed JWT. The client then sends this token with subsequent requests. The server verifies the token and determines whether the request is authorized.

Spring Security supports JWT validation through its OAuth 2.0 Resource Server functionality. For many applications, this built-in support is preferable to creating a custom JWT authentication filter and manually implementing token validation.

Why Use JWT Authentication?

  • It supports stateless API authentication when configured appropriately.
  • It is suitable for web applications, mobile applications, and REST APIs.
  • It can carry claims such as a user identifier, issuer, audience, and expiration time.
  • It can be validated by multiple services when they trust the same issuer and signing keys.
  • It integrates with Spring Security authorization rules.
  • It avoids the need to look up a server-side session for every request when the application uses a genuinely stateless design.

2. What Is a JSON Web Token?

A JWT is a string consisting of three Base64URL-encoded parts separated by periods. A typical signed JWT has the following structure:

header.payload.signature

The three components are the header, payload, and signature.

Component Description Example Information
Header Specifies the token type and signing algorithm. alg, typ
Payload Contains claims describing the subject and token context. sub, iss, exp
Signature Allows the receiver to verify the integrity and authenticity of the signed token. Cryptographic signature

Important: A signed JWT is not necessarily encrypted. Its header and payload can usually be decoded by anyone who obtains the token. Never place passwords, private keys, or confidential personal information in ordinary JWT claims.

3. Understanding JWT Claims

Claims are statements included in a JWT payload. Some claims have standardized meanings, while others are application-specific.

Claim Purpose
sub Identifies the subject, often a user identifier.
iss Identifies the token issuer.
aud Identifies the intended recipient or audience.
iat Indicates when the token was issued.
exp Indicates when the token expires.
nbf Indicates the time before which the token must not be accepted.
jti Provides a unique token identifier when included.

JWT validation should verify more than the token's structure. Depending on the application, it should validate the signature, expiration, issuer, audience, and other relevant claims.

4. How JWT Authentication Works

JWT authentication commonly involves an authentication service that issues tokens and an API that validates them. These may be separate services or components of the same application.

Authentication Workflow

  1. The client submits its username and password over HTTPS to an authentication endpoint.
  2. The server verifies the credentials using a configured authentication provider.
  3. If authentication succeeds, the authentication system issues a signed access token.
  4. The client stores the token using a storage mechanism appropriate to its security model.
  5. The client sends the token in the HTTP Authorization header when requesting a protected API.
  6. Spring Security extracts the bearer token and validates its signature and configured claims.
  7. If the token is valid, Spring Security establishes the authenticated security context for the request.
  8. Authorization rules determine whether the authenticated principal has permission to access the requested resource.
  9. If authentication or authorization fails, the application returns the appropriate error response.

Example HTTP Request

GET /api/profile HTTP/1.1
Host: localhost:8080
Authorization: Bearer eyJhbGciOiJSUzI1NiJ9.example.signature

The token shown above is illustrative and is not a valid access token.

5. JWT Authentication Architecture in Spring Security

Spring Security provides built-in components for processing bearer tokens and authenticating JWTs.

Component Responsibility
SecurityFilterChain Configures request matching, authentication mechanisms, and authorization rules.
BearerTokenAuthenticationFilter Extracts bearer tokens from supported requests and initiates authentication.
AuthenticationManager Coordinates authentication using configured authentication providers.
JwtAuthenticationProvider Authenticates JWT-based bearer tokens.
JwtDecoder Decodes JWTs and verifies signatures and configured token claims.
JwtAuthenticationConverter Converts a validated JWT into an authenticated principal and granted authorities.
SecurityContextHolder Provides access to the current request's security context.

Spring Security's Resource Server support can perform JWT validation without requiring developers to write a custom token-processing filter.

6. Setting Up a Spring Boot Project

Create a Spring Boot project with Spring Web, Spring Security, and OAuth 2.0 Resource Server dependencies.

Required Maven Dependencies

Add the following dependencies to the project's pom.xml. Manage versions through the Spring Boot parent or dependency management configuration.

<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-security</artifactId>
    </dependency>

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-oauth2-resource-server</artifactId>
    </dependency>
</dependencies>

The Resource Server starter brings in the components used for bearer-token authentication. JWT decoding and verification support is provided through the related OAuth 2.0 JOSE functionality.

7. Configuring the JWT Resource Server

When an application receives tokens issued by a trusted identity provider, Spring Boot can configure JWT validation through application properties.

Example application.yml

spring:
  security:
    oauth2:
      resourceserver:
        jwt:
          issuer-uri: https://identity.example.com/issuer

Replace the example issuer with the actual issuer URI of your trusted authorization server. The issuer must support the discovery mechanism expected by Spring Security, or the application must use an appropriate alternative configuration.

With a supported issuer configuration, Spring Security can discover the issuer's public signing keys and validate incoming JWTs. The identity provider is responsible for authenticating users and issuing tokens.

Configure the Security Filter Chain

package com.example.security;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.Customizer;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.web.SecurityFilterChain;

@Configuration
public class SecurityConfig {

    @Bean
    public SecurityFilterChain securityFilterChain(
            HttpSecurity http) throws Exception {

        http
            .csrf(csrf -> csrf.disable())
            .sessionManagement(session -> session
                .sessionCreationPolicy(
                    SessionCreationPolicy.STATELESS
                )
            )
            .authorizeHttpRequests(authorize -> authorize
                .requestMatchers("/api/public/**").permitAll()
                .requestMatchers("/api/admin/**")
                    .hasRole("ADMIN")
                .anyRequest().authenticated()
            )
            .oauth2ResourceServer(oauth2 -> oauth2
                .jwt(Customizer.withDefaults())
            );

        return http.build();
    }
}

Explanation

  • SecurityFilterChain defines the security policy for matching requests.
  • csrf(csrf -> csrf.disable()) disables CSRF protection for this chain. This is appropriate only when the application's architecture makes that choice safe; it should not be copied indiscriminately into browser applications that use cookies or sessions.
  • SessionCreationPolicy.STATELESS prevents Spring Security from using an HTTP session to obtain the security context for each request.
  • permitAll() allows public access to the specified endpoint pattern.
  • hasRole("ADMIN") requires the corresponding ROLE_ADMIN authority.
  • authenticated() requires the request to be authenticated.
  • oauth2ResourceServer() enables bearer-token processing.
  • jwt() configures JWT support using Spring Security's resource-server infrastructure.

Note: This example configures an API that validates tokens; it does not implement a username-and-password login endpoint or issue JWTs. Token issuance is normally handled by an authorization server or by a separately designed authentication component.

8. Implementing a Login Endpoint

A login endpoint accepts credentials and verifies them against the application's user store. A successful login may result in the issuance of an access token. The following example demonstrates credential authentication using Spring Security's AuthenticationManager; it intentionally leaves token issuance to a trusted token service.

Login Request DTO

package com.example.auth;

public record LoginRequest(
    String username,
    String password
) {}

Authentication Service Interface

package com.example.auth;

public interface AccessTokenService {
    String createAccessToken(String username);
}

Implement AccessTokenService using a maintained JWT library or integrate with an authorization server. The implementation must use a secure signing key and include suitable token claims, expiration, and issuer information.

Authentication Controller

package com.example.auth;

import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication
    .UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.web.bind.annotation.*;

@RestController
@RequestMapping("/auth")
public class AuthController {

    private final AuthenticationManager authenticationManager;
    private final AccessTokenService accessTokenService;

    public AuthController(
            AuthenticationManager authenticationManager,
            AccessTokenService accessTokenService) {
        this.authenticationManager = authenticationManager;
        this.accessTokenService = accessTokenService;
    }

    @PostMapping("/login")
    public ResponseEntity<TokenResponse> login(
            @RequestBody LoginRequest request) {

        Authentication authentication =
            authenticationManager.authenticate(
                new UsernamePasswordAuthenticationToken(
                    request.username(),
                    request.password()
                )
            );

        String token = accessTokenService.createAccessToken(
            authentication.getName()
        );

        return ResponseEntity.ok(new TokenResponse(token));
    }

    public record TokenResponse(String accessToken) {}
}

This controller illustrates the flow, but it requires a configured AuthenticationManager, a suitable user authentication provider, and a working AccessTokenService implementation. It does not constitute a complete production authentication system on its own.

In production, handle authentication exceptions through a centralized exception handler, validate request fields, apply login rate limits, and avoid revealing whether a particular username exists.

9. Configuring User Authentication

For a database-backed application, credentials should be verified through a properly configured UserDetailsService and a password encoder. Passwords must never be stored or compared as plaintext.

Example Password Encoder

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.crypto.bcrypt
    .BCryptPasswordEncoder;
import org.springframework.security.crypto.password
    .PasswordEncoder;

@Configuration
public class PasswordConfig {

    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }
}

Use the same encoder policy when storing and verifying passwords. For real applications, user accounts should also support account status checks, appropriate password-reset flows, and protections against repeated login attempts.

10. Understanding Access Tokens and Refresh Tokens

Access tokens and refresh tokens serve different purposes. An access token is presented to protected APIs. A refresh token can be exchanged for a new access token according to the authorization server's policy.

Feature Access Token Refresh Token
Primary purpose Access protected resources Obtain a new access token
Typical lifetime Relatively short Often longer, subject to policy
Sent to resource APIs Yes, as a bearer token Normally no
Storage and handling Must be protected from theft Requires particularly careful protection
Revocation strategy May remain usable until expiry unless additional controls exist Can be revoked or rotated by the issuing system

JWTs do not automatically provide refresh-token support. The application must implement or integrate with a token-issuing service that handles refresh, expiration, rotation, and revocation securely.

11. Protecting REST API Endpoints

After configuring JWT validation, controllers can expose endpoints with different access requirements.

Example REST Controller

package com.example.api;

import java.util.Map;

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("/api")
public class ProfileController {

    @GetMapping("/public/info")
    public Map<String, String> publicInfo() {
        return Map.of(
            "message",
            "This endpoint is publicly accessible"
        );
    }

    @GetMapping("/profile")
    public Map<String, String> profile() {
        return Map.of(
            "message",
            "This endpoint requires authentication"
        );
    }

    @GetMapping("/admin/dashboard")
    public Map<String, String> adminDashboard() {
        return Map.of(
            "message",
            "Administrator access granted"
        );
    }
}

The controller endpoints must be matched by the security rules defined earlier. Requests to protected endpoints must include a valid bearer token. An authenticated principal must also possess the authority required by any role or permission restrictions.

12. Role-Based Authorization with JWT

JWT authentication establishes the identity represented by a token, but applications must also determine what that identity is permitted to do. Spring Security can use scopes and granted authorities to enforce authorization.

Example Authorization Rules

http.authorizeHttpRequests(authorize -> authorize
    .requestMatchers("/api/public/**").permitAll()
    .requestMatchers("/api/admin/**").hasRole("ADMIN")
    .requestMatchers("/api/reports/**")
        .hasAuthority("REPORT_READ")
    .anyRequest().authenticated()
);

The authority mapping depends on the token issuer and the configured converter. Spring Security's default JWT resource-server configuration maps scopes to authorities prefixed with SCOPE_. For example, the scope reports commonly becomes SCOPE_reports.

For tokens that contain custom roles, configure a suitable authority converter and validate that the claims are issued by a trusted authorization server. Do not treat arbitrary client-supplied claims as trusted permissions.

13. Handling Expired or Invalid Tokens

A protected API must reject tokens that fail validation. Common reasons include an invalid signature, an expired token, an invalid issuer, a token that is not yet valid, or a token intended for another audience.

HTTP Status Meaning
200 OK The request succeeded.
401 Unauthorized Authentication is missing or invalid, such as when a bearer token is expired or malformed.
403 Forbidden The request is authenticated but is not authorized, or another applicable security policy denies access.

The precise response depends on the authentication mechanism and application configuration. Avoid exposing cryptographic details, secrets, or internal stack traces in authentication error messages.

14. Testing JWT Authentication

Testing should cover successful authentication, invalid credentials, token validation, and authorization decisions. Spring Security's test support can create mock JWT authentication for authorization tests, while integration tests should also verify the configured decoder and real token-validation behavior.

Example: Testing an Authenticated Endpoint

Add the Spring Security test dependency to your test configuration:

<dependency>
    <groupId>org.springframework.security</groupId>
    <artifactId>spring-security-test</artifactId>
    <scope>test</scope>
</dependency>

Example using MockMvc and a mock JWT:

import static org.springframework.test.web.servlet.request
    .MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.result
    .MockMvcResultMatchers.status;

import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet
    .AutoConfigureMockMvc;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.web.servlet.MockMvc;

import static org.springframework.security.test.web.servlet
    .request.SecurityMockMvcRequestPostProcessors.jwt;

@SpringBootTest
@AutoConfigureMockMvc
class JwtSecurityTest {

    @Autowired
    private MockMvc mockMvc;

    @Test
    void authenticatedUserCanAccessProfile() throws Exception {
        mockMvc.perform(get("/api/profile")
                .with(jwt()))
            .andExpect(status().isOk());
    }
}

This test supplies a mock authenticated JWT through Spring Security's test support. It tests authorization behavior but does not prove that a real signed token is correctly validated. Add integration tests for invalid signatures, expired tokens, issuer validation, audience validation, and missing bearer tokens.

Recommended Test Scenarios

  • Login succeeds with valid credentials.
  • Login fails with invalid credentials.
  • Protected endpoints reject missing tokens.
  • Protected endpoints reject expired or invalid tokens.
  • Public endpoints remain accessible without a token.
  • Users with insufficient authorities receive an appropriate denial response.
  • Issuer, audience, and timestamp validation work as intended.
  • Token refresh and revocation behavior are tested if supported.

15. Common JWT Authentication Errors and Solutions

Problem Possible Cause Solution
401 Unauthorized Missing, malformed, expired, or invalid bearer token. Check the Authorization header, token expiration, and decoder configuration.
403 Forbidden The authenticated principal lacks the required authority. Review roles, scopes, authority mapping, and authorization rules.
Invalid signature The token was signed with an untrusted key or the wrong algorithm. Verify the issuer's signing keys and allowed algorithms.
Issuer validation failure The token's issuer does not match the configured issuer. Use the correct issuer URI and verify the token's iss claim.
Audience validation failure The token was issued for a different resource or client. Configure and validate the expected audience.
Token appears expired The expiration claim has passed or server clocks differ. Check token lifetime and system clock synchronization.
Login endpoint is inaccessible The endpoint is not permitted by the security rules or the login flow is misconfigured. Permit the intended login endpoint and verify the authentication setup.
JWT role is ignored The token's custom role claim is not mapped to Spring authorities. Configure a suitable JWT authentication converter.

16. JWT Authentication Security Best Practices

  • Always use HTTPS for authentication and API traffic.
  • Use a trusted authorization server or a carefully implemented token service.
  • Prefer maintained security libraries instead of manually implementing cryptographic verification.
  • Allow only explicitly trusted signing algorithms and validate signatures.
  • Validate issuer, audience, expiration, and other required claims.
  • Keep access-token lifetimes appropriately short for the application's risk level.
  • Protect signing keys and secrets using a secure secret-management solution.
  • Never store passwords or signing secrets inside JWT payloads.
  • Protect tokens against theft through suitable client-side storage and transport decisions.
  • Use secure, HttpOnly, and appropriate SameSite cookie settings when cookies are part of the design.
  • Do not disable CSRF protection without evaluating how credentials are transmitted and whether browsers attach them automatically.
  • Implement rate limiting and monitoring for authentication endpoints.
  • Use refresh-token rotation and revocation controls when refresh tokens are supported.
  • Do not log full access tokens, refresh tokens, or credentials.
  • Keep Spring Boot, Spring Security, and JWT-related dependencies updated.

17. Practical Project: JWT-Secured Employee Management API

Build a Spring Boot REST API that authenticates employees and protects resources with JWT access tokens.

Project Requirements

  • Create a login endpoint that authenticates employee credentials.
  • Issue a signed access token after successful authentication.
  • Allow public access to selected informational endpoints.
  • Require authentication for employee profile endpoints.
  • Restrict administrative operations to users with the appropriate role.
  • Validate token signatures and relevant claims on protected requests.
  • Return suitable responses for unauthenticated and unauthorized requests.
  • Write unit and integration tests for authentication and authorization.

Suggested Project Structure

src/main/java/com/example
    ├── auth
    │   ├── AuthController.java
    │   ├── LoginRequest.java
    │   └── AccessTokenService.java
    ├── security
    │   └── SecurityConfig.java
    ├── api
    │   └── ProfileController.java
    └── EmployeeApplication.java

src/test/java/com/example
    └── JwtSecurityTest.java

The project structure is illustrative. You may add repository, service, entity, and database configuration packages when integrating a persistent user store.

18. Interview Questions and Answers

Q1. What is JWT?

Answer: JSON Web Token is a compact, URL-safe token format used to carry claims between parties. Signed JWTs allow receivers to verify integrity and authenticity when the signature and relevant claims are validated.

Q2. What are the three parts of a signed JWT?

Answer: The header, payload, and signature. They are separated by periods.

Q3. Is JWT encrypted by default?

Answer: No. A typical signed JWT is readable by anyone who obtains it. Signing protects integrity, not confidentiality.

Q4. What is the difference between authentication and authorization?

Answer: Authentication verifies identity. Authorization determines which resources or operations the authenticated identity is allowed to access.

Q5. What is a bearer token?

Answer: A bearer token is a credential that grants access to whoever possesses it, subject to the resource server's validation and authorization policies. It must be protected against theft.

Q6. How does Spring Security validate JWTs?

Answer: Its Resource Server support uses components such as BearerTokenAuthenticationFilter, JwtAuthenticationProvider, and JwtDecoder to process and validate bearer tokens.

Q7. Why is token expiration important?

Answer: Expiration limits the time during which a stolen token can be used. The resource server must validate the token's expiration claim.

Q8. What is the purpose of the issuer claim?

Answer: The iss claim identifies the entity that issued the token. Validating it helps ensure the token comes from the expected trusted issuer.

Q9. What is the difference between an access token and a refresh token?

Answer: An access token is used to access protected resources. A refresh token is used with the issuing system to obtain a new access token according to its refresh policy.

Q10. Why use SessionCreationPolicy.STATELESS?

Answer: It configures Spring Security not to use an HTTP session to obtain the security context for each request, which is useful for many bearer-token APIs.

Q11. What is the difference between HTTP 401 and HTTP 403?

Answer: A 401 response typically indicates missing or invalid authentication. A 403 response typically indicates that the request is not permitted, often because the authenticated principal lacks sufficient permissions.

Q12. Should developers implement their own JWT validation filter?

Answer: Usually not when Spring Security's built-in Resource Server support meets the requirements. Its established components reduce the risk of mistakes in token extraction, signature verification, and security-context handling.

19. Quick Revision Checklist

  • Understand JWT structure and claims.
  • Know the difference between signing and encryption.
  • Configure Spring Security Resource Server dependencies.
  • Configure a trusted issuer or appropriate public-key source.
  • Define a SecurityFilterChain bean.
  • Enable JWT bearer-token authentication.
  • Protect endpoints using authentication and authorization rules.
  • Validate signatures, expiration, issuer, and audience where required.
  • Keep authentication and token issuance separate from token validation when appropriate.
  • Test invalid tokens and authorization failures.
  • Protect tokens and signing keys.

20. Conclusion

JWT-based authentication is a widely used approach for securing Spring Boot REST APIs. By combining a trusted token issuer with Spring Security's OAuth 2.0 Resource Server support, developers can validate bearer tokens, establish authenticated principals, and enforce access-control policies.

A reliable implementation requires more than generating a token. It must also validate signatures and claims, manage token lifetimes, protect credentials, configure authorization correctly, and test failure scenarios.

To learn more about Java, Spring Boot, and application security, visit the Advanced Java Training Course at JustAcademy.

You can also register for a course demo or explore other learning resources on the JustAcademy website.

Reference Documentation

For official implementation details, refer to the Spring Security JWT Resource Server documentation.

Previous Next
whatsapp